/**
 * @main.cpp
 * This file is part of FEGRF.
 * 
 * FEGRF is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * See LICENSE file in main folder for more information.
 */

#include <wx/wxprec.h>

#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif

#include "list.h"
#include "main.h"
#include "frame.h"
#include "resource.h"

#include <wx/dir.h>
#include <wx/file.h>
#include <wx/filename.h>
#include <wx/listimpl.cpp>
#include <wx/progdlg.h>
#include <wx/wfstream.h>

#if defined( __WXMSW__ ) && defined( _DEBUG )
#include <wx/msw/msvcrt.h>
#endif

IMPLEMENT_APP(MyApp)

WX_DEFINE_LIST(MyDataList);

BEGIN_EVENT_TABLE(MainFrame, wxFrame)
	EVT_TOOL(BTN_NEW, MainFrame::OnToolbarNew)
	EVT_TOOL(BTN_OPEN, MainFrame::OnToolbarOpen)
	EVT_TOOL(BTN_CLOSE, MainFrame::OnToolbarClose)
	EVT_TOOL(BTN_VIEW, MainFrame::OnToolbarView)
	EVT_TOOL(BTN_REPACK, MainFrame::OnToolbarRepack)
	EVT_TOOL(BTN_INSERT, MainFrame::OnToolbarInsert)
	EVT_TOOL(BTN_EXTRACT, MainFrame::OnToolbarExtract)
	EVT_TOOL(BTN_DELETE, MainFrame::OnToolbarDelete)
	EVT_TOOL(BTN_SETTING, MainFrame::OnToolbarSetting)
	EVT_TEXT_ENTER(FILTER_TEXT, MainFrame::OnToolbarFilter)
	EVT_DATAVIEW_ITEM_ACTIVATED(LIST_GRF, MainFrame::OnListDClick)
	EVT_DATAVIEW_ITEM_CONTEXT_MENU(LIST_GRF, MainFrame::OnPopMenu)
	EVT_MENU(POP_RENAME, MainFrame::OnPopRename)
	EVT_MENU(POP_VIEW, MainFrame::OnPopView)
	EVT_MENU(POP_EXTRACT_SELECTED, MainFrame::OnPopExtract)
	EVT_MENU(POP_EXTRACT_ALL, MainFrame::OnPopExtractAll)
	EVT_MENU(POP_DELETE, MainFrame::OnPopDelete)
	EVT_CHAR_HOOK(MainFrame::OnKeyPressed)
	EVT_CLOSE(MainFrame::OnCloseWindow)
END_EVENT_TABLE()

MainFrame::MainFrame(const wxString &title, const wxPoint &pos, const wxSize &size)
	:wxFrame(NULL, wxID_ANY, title, pos, size)
{
	SetIcon(wxICON(FE_ICON));
	SetMinSize(size);
	Center();
	SettingsLoad();
	SetBackgroundColour(wxColour(0xFFFFFF));

	// Set List
	m_grf_data = new MyDataList();
	m_grf_list = new MyDataViewCtrl(this, LIST_GRF, wxDefaultPosition, wxDefaultSize, wxDV_MULTIPLE | wxDV_HORIZ_RULES | wxBORDER_NONE);
	m_grf_list->SetEncoding(m_config->ReadLong(_("/Settings/Encoding"), ENC_LOCAL));
	m_grf_list->SetDropTarget(new DnDFile(this));

	// Set Toolbar
	ToolbarImage toolbar_image;
	m_toolbar = CreateToolBar(wxNO_BORDER | wxTB_FLAT | wxTB_HORIZONTAL | wxTB_NODIVIDER);
	m_toolbar->AddTool(BTN_NEW, _("New"), wxBitmap(toolbar_image.png_new), _("New"))->SetLongHelp(_("Create a new GRF"));
	m_toolbar->AddTool(BTN_OPEN, _("Open"), wxBitmap(toolbar_image.png_open), _("Open"))->SetLongHelp(_("Open existing GRF or GPF"));
	m_toolbar->AddTool(BTN_CLOSE, _("Close"), wxBitmap(toolbar_image.png_close), _("Close"))->SetLongHelp(_("Close current GRF"));
	m_toolbar->AddSeparator();
	m_toolbar->AddTool(BTN_VIEW, _("View"), wxBitmap(toolbar_image.png_view), _("View"))->SetLongHelp(_("View file content"));
	m_toolbar->AddTool(BTN_REPACK, _("Repack"), wxBitmap(toolbar_image.png_repack), _("Repack"))->SetLongHelp(_("Repack entire GRF"));
	m_toolbar->AddTool(BTN_INSERT, _("Insert"), wxBitmap(toolbar_image.png_insert), _("Insert"))->SetLongHelp(_("Insert file from Directory or GRF to current GRF"));
	m_toolbar->AddTool(BTN_EXTRACT, _("Extract"), wxBitmap(toolbar_image.png_extract), _("Extract"))->SetLongHelp(_("Extract file from GRF"));
	m_toolbar->AddTool(BTN_DELETE, _("Delete"), wxBitmap(toolbar_image.png_delete), _("Delete"))->SetLongHelp(_("Delete file inside GRF"));
	m_toolbar->AddSeparator();
	m_toolbar->AddTool(BTN_SETTING, _("Setting"), wxBitmap(toolbar_image.png_setting), _("Setting"))->SetLongHelp(_("Change settings"));
	m_toolbar->AddStretchableSpace();
	m_filter = new wxSearchCtrl(m_toolbar, FILTER_TEXT, wxEmptyString, wxDefaultPosition, wxSize(250, -1), wxTE_PROCESS_ENTER);
	m_toolbar->AddControl(m_filter);
	m_toolbar->Realize();
	m_read_only = false;
	ToolbarEnable(false);

	// Status Bar
	int status_bar_width[] = { -1, 80, 120 };
	CreateStatusBar(3);
	SetStatusText(_(""), 0);
	SetStatusText(_(""), 1);
	SetStatusText(_(""), 2);
	SetStatusWidths(3, status_bar_width);
}

MainFrame::~MainFrame()
{
	SettingsSave();
	DataClear();
	delete m_config;
	delete m_grf_data;
}

void MainFrame::OnToolbarNew(wxCommandEvent &WXUNUSED(event))
{
	wxFileDialog file_save_dialog(NULL, _("Save As"), m_config->Read(_("/History/LastDirectory"), wxEmptyString), _(".grf"), _("GRF Files (*.grf)|*.grf"), wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
	if (file_save_dialog.ShowModal() != wxID_OK)
		return;

	m_config->Write("/History/LastDirectory", file_save_dialog.GetDirectory());
	FileNew(file_save_dialog.GetPath());
}

void MainFrame::OnToolbarOpen(wxCommandEvent &WXUNUSED(event))
{	
	wxFileDialog file_open_dialog(NULL, _("Load"), m_config->Read(_("/History/LastDirectory"), wxEmptyString), wxEmptyString, _("GRF Files (*.grf; *.gpf)|*.grf;*.gpf"), wxFD_OPEN | wxFD_FILE_MUST_EXIST);
	if (file_open_dialog.ShowModal() != wxID_OK)
		return;

	m_config->Write("/History/LastDirectory", file_open_dialog.GetDirectory());
	FileOpen(file_open_dialog.GetPath());
}

void MainFrame::OnToolbarClose(wxCommandEvent &WXUNUSED(event))
{
	GRFClose();
}

void MainFrame::OnToolbarFilter(wxCommandEvent &WXUNUSED(event))
{
	if (m_toolbar->GetToolEnabled(BTN_CLOSE))
		FileFilter();
}

void MainFrame::OnToolbarView(wxCommandEvent &WXUNUSED(event))
{
	FileView();
}

void MainFrame::OnToolbarRepack(wxCommandEvent &WXUNUSED(event))
{
	uint32_t wasted = grf_wasted_space(m_grf_handle);
	if (wxMessageBox((wasted == 0 || wasted > wxFile(m_grf_path).Length()) ? _("Repacking this file will not reduce it size.\nDo you want to continue?") : wxString::Format("Repacking this file will reduce it size by %s.\nDo you want to continue?", ConvertByte(wasted)), _("Repack"), wxYES_NO) == wxYES)
		FileRepack(m_config->ReadLong("/Settings/RepackType", GRF_REPACK_FAST));
}

void MainFrame::OnToolbarInsert(wxCommandEvent &WXUNUSED(event))
{
	GRFDialog dialog_insert(this, DIALOG_INSERT, _("Insert File"), wxDefaultPosition, wxSize(180, 110));
	FileInsert(dialog_insert.ShowModal());
}

void MainFrame::OnToolbarExtract(wxCommandEvent &WXUNUSED(event))
{
	DialogExtract();
}

void MainFrame::OnToolbarDelete(wxCommandEvent &WXUNUSED(event))
{
	DialogDelete();
}

void MainFrame::OnToolbarSetting(wxCommandEvent &WXUNUSED(event))
{
	DialogSetting();
}

void MainFrame::ToolbarEnable(bool enable)
{
	//Disable/Enable button upon open/close GRF File
	m_toolbar->EnableTool(BTN_CLOSE, enable);
	m_toolbar->EnableTool(BTN_VIEW, enable);
	m_toolbar->EnableTool(BTN_REPACK, (!m_read_only && enable));
	m_toolbar->EnableTool(BTN_INSERT, (!m_read_only && enable));
	m_toolbar->EnableTool(BTN_EXTRACT, enable);
	m_toolbar->EnableTool(BTN_DELETE, (!m_read_only && enable));
	m_toolbar->Refresh();
}

void MainFrame::OnListDClick(wxDataViewEvent &WXUNUSED(event))
{
	if (!m_grf_data->IsEmpty())
		FileView();
}

void MainFrame::OnPopMenu(wxDataViewEvent &WXUNUSED(event))
{
	if (!m_toolbar->GetToolEnabled(BTN_CLOSE))
		return;
	m_pop_menu = new wxMenu();
	m_pop_menu->Append(POP_EXTRACT_SELECTED, _("Extract Selected\tCtrl+X"));
	m_pop_menu->Append(POP_EXTRACT_ALL, _("Extract All"));
	m_pop_menu->AppendSeparator();
	m_pop_menu->Append(POP_VIEW, _("View"));
	m_pop_menu->Append(POP_DELETE, _("Delete Selected\tDelete"))->Enable(!m_read_only);
	if (m_grf_list->GetSelectedItemsCount() == 1)
		m_pop_menu->Append(POP_RENAME, _("Rename\tCtrl+R"))->Enable(!m_read_only);
	m_grf_list->PopupMenu(m_pop_menu);
	delete m_pop_menu;
}

void MainFrame::OnPopRename(wxCommandEvent &WXUNUSED(event))
{
	m_grf_list->StartEdit(m_grf_list->GetSelection());
}

void MainFrame::OnPopView(wxCommandEvent &WXUNUSED(event))
{
	FileView();
}

void MainFrame::OnPopExtract(wxCommandEvent &WXUNUSED(event))
{
	DialogExtract();
}

void MainFrame::OnPopExtractAll(wxCommandEvent &WXUNUSED(event))
{
	m_grf_list->SelectAll();
	DialogExtract();
}

void MainFrame::OnPopDelete(wxCommandEvent &WXUNUSED(event))
{
	DialogDelete();
}

void MainFrame::OnKeyPressed(wxKeyEvent &event)
{
	event.Skip();
	if (IsActive()) {
		switch (event.GetModifiers()) {
			case wxMOD_CONTROL:
				switch (event.GetKeyCode()) {
					case 'A':
						if (!m_grf_data->IsEmpty())
							m_grf_list->SelectAll();
						break;
					case 'F':
						m_filter->SetFocus();
						break;
					case 'O':
						OnToolbarOpen((wxCommandEvent)NULL);
						break;
					case 'R':
						if (!m_grf_data->IsEmpty() && !m_read_only && m_grf_list->GetSelectedItemsCount() == 1 && m_grf_list->GetSelections((wxDataViewItemArray)NULL) == 1)
							m_grf_list->StartEdit(m_grf_list->GetSelection());
						break;
					case 'X':
						if (!m_grf_data->IsEmpty())
							DialogExtract();
						break;
					default:
						break;
				} break;
			case wxMOD_NONE:
				if (event.GetKeyCode() == WXK_DELETE)
					if (!m_grf_data->IsEmpty() && !m_read_only)
						DialogDelete();
			default:
				break;
		}
	}
}

void MainFrame::OnCloseWindow(wxCloseEvent &event)
{
	event.Skip();

	if (m_toolbar->GetToolEnabled(BTN_CLOSE)) {
		DataClear();
		m_grf_list->Resize(0);
		grf_free(m_grf_handle);
	}
}

void MainFrame::OnExtract()
{
	wxString file_path = wxEmptyString;

	wxDirDialog dir_dialog(this, _("Extract to:"), wxEmptyString, wxDD_DEFAULT_STYLE);
	if (dir_dialog.ShowModal() == wxID_OK)
		file_path = dir_dialog.GetPath();
	else return;
	if (!file_path.EndsWith('\\'))
		file_path.Append('\\');
	
	wxString file_save = wxEmptyString;
	int flag = 0;
	GrfNode *grf_node = NULL;
	wxArrayString error_message;

	if (m_config->ReadBool(_("/Settings/ExtractWithDirectory"), true))
		flag |= EXTRACT_WITH_DIRECTORY;
	if (m_config->ReadBool(_("/Settings/ExtractConvertToANSI"), true))
		flag |= EXTRACT_CONVERT_ASCII;

	m_grf_list->Enable(false);

	m_progress = new wxProgressDialog(_("Extracting to ") + file_path, wxEmptyString, m_grf_data->GetCount(), this, wxPD_AUTO_HIDE | wxPD_CAN_ABORT | wxPD_APP_MODAL);
	for (int i = 0; i < m_grf_data->GetCount(); i++) {
		if (!m_progress->Update(i, file_save))
			break;

		if (m_grf_list->IsSelected(m_grf_list->GetItem(i))) {
			grf_node = grf_get_file(m_grf_handle, m_grf_data->Item(i)->GetData()->name.mb_str());
			if (grf_node == NULL)
				continue;
			if (flag&EXTRACT_WITH_DIRECTORY)
				file_save = wxString::From8BitData(file_path+grf_file_get_filename(grf_node));
			else
				file_save = wxString::From8BitData(file_path+grf_file_get_basename(grf_node));
			if (!FileExtract(grf_node, file_save, flag&EXTRACT_CONVERT_ASCII ? 1 : 0))
				error_message.Add(file_path+m_grf_data->Item(i)->GetData()->name);
		}
	}

	m_progress->Destroy();
	m_grf_list->Enable();

	if (error_message.size()) {
		GRFDialog dialog_error(this, DIALOG_EXTRACT_ERROR, _("Error"), wxDefaultPosition, wxSize(350, 400));
		dialog_error.AddList(error_message);
		dialog_error.ShowModal();
	}
}

void MainFrame::OnDelete()
{
	wxString file_path = wxEmptyString;
	GrfNode *grf_node = NULL;
	m_progress = new wxProgressDialog(_("Deleting"), wxEmptyString, m_grf_data->GetCount(), NULL, wxPD_AUTO_HIDE | wxPD_CAN_ABORT);
	for (int i = 0; i < m_grf_data->GetCount(); i++) {
		if (!m_progress->Update(i, file_path))
			break;

		if (m_grf_list->IsSelected(m_grf_list->GetItem(i))) {
			file_path = m_grf_data->Item(i)->GetData()->name;
			grf_node = grf_get_file(m_grf_handle, file_path);
			grf_file_delete(grf_node);
		}
	}
	m_progress->Destroy();

	GRFRead();
}

void MainFrame::GRFRead()
{
	DataClear();
	GrfNode *grf_node = grf_get_file_first(m_grf_handle);

	if (m_grf_data->GetCount())
		m_grf_data->Clear();

	uint64_t size_real = 0,
	         size_comp = 0;
	wxProgressDialog progress_dialog(_("Reading ") + m_grf_path, wxEmptyString, grf_filecount(m_grf_handle), NULL, wxPD_AUTO_HIDE | wxPD_CAN_ABORT);
	while (grf_node != NULL) {
		MyData *data = new MyData;
		data->name = wxString::From8BitData(grf_file_get_filename(grf_node));
		data->type = GetExtension(grf_file_get_filename(grf_node));
		data->size = grf_file_get_size(grf_node);
		data->pack = grf_file_get_storage_size(grf_node);
		m_grf_data->Append(data);

		if (!progress_dialog.Update(progress_dialog.GetValue() + 1, data->name)) {
			GRFClose();
			return;
		}

		size_real += grf_file_get_size(grf_node);
		size_comp += grf_file_get_storage_size(grf_node);

		grf_node = grf_get_file_next(grf_node);
	}
	progress_dialog.Update(progress_dialog.GetRange());
	m_grf_list->Resize(grf_filecount(m_grf_handle));
	ToolbarEnable(true);
	SetStatusText(m_grf_path, 0);
	SetStatusText(wxString::Format("%d Files", grf_filecount(m_grf_handle)), 1);
	SetStatusText(ConvertByte(size_real, size_comp), 2);

	if (!m_filter->IsEmpty())
		FileFilter();
}

void MainFrame::GRFClose()
{
	m_grf_list->Resize(0);
	DataClear();
	m_read_only = false;
	ToolbarEnable(false);
	SetStatusText(_(""), 0);
	SetStatusText(_(""), 1);
	SetStatusText(_(""), 2);
	grf_free(m_grf_handle);
	if (FindWindow(FRAME_VIEW))
		m_view->Close();
}

bool MainFrame::FileNew(const wxString &file_path)
{
	m_grf_path = file_path;
	if (m_toolbar->GetToolEnabled(BTN_CLOSE))
		GRFClose();

	if (wxFileExists(file_path) && !wxFile::Access(file_path, wxFile::read_write)) {
		wxMessageBox(_("Opening this file in read-only mode"), _("Info"), wxOK | wxICON_INFORMATION);
		m_read_only = true;
	} else
		m_read_only = false;

	m_grf_handle = grf_new(file_path.mb_str(), !m_read_only);
	grf_set_compression_level(m_grf_handle, m_config->ReadLong(_("/Settings/CompressionLevel"), 5));

	ToolbarEnable(true);
	SetStatusText(file_path, 0);
	SetStatusText(wxString::Format("%d Files", 0), 1);
	SetStatusText(wxString::Format("%d /", 0) + wxString::Format(" %d ", 0) + _("B"), 2);
	return true;
}

bool MainFrame::FileOpen(const wxString &file_path)
{
	m_grf_path = file_path;
	if (m_toolbar->GetToolEnabled(BTN_CLOSE))
		GRFClose();

	if (wxFileExists(file_path) && !wxFile::Access(file_path, wxFile::read_write)) {
		wxMessageBox(_("Opening this file in read-only mode"), _("Info"), wxOK | wxICON_INFORMATION);
		m_read_only = true;
	} else
		m_read_only = false;

	m_grf_handle = grf_load(file_path.mb_str(), !m_read_only);
	if (m_grf_handle == NULL) {
		wxMessageBox(_("Invalid GRF"), _("Error"), wxICON_ERROR);
		return false;
	}

	grf_set_compression_level(m_grf_handle, m_config->ReadLong(_("/Settings/CompressionLevel"), 5));
	GRFRead();
	SetFocus();
	return true;
}

void MainFrame::FileFilter()
{
	DataClear();
	GrfNode *grf_node = grf_get_file_first(m_grf_handle);

	uint32_t file_count = 0;
	wxProgressDialog progress_dialog(_("Filtering..."), wxEmptyString, grf_filecount(m_grf_handle), NULL, wxPD_AUTO_HIDE | wxPD_CAN_ABORT);
	while (grf_node != NULL) {
		if (wxString(grf_file_get_filename(grf_node), wxConvLocal).Contains(wxString(m_filter->GetValue().To8BitData(), wxConvLocal))) {
			MyData *data = new MyData;
			data->name = wxString::From8BitData(grf_file_get_filename(grf_node));
			data->type = GetExtension(grf_file_get_filename(grf_node));
			data->size = grf_file_get_size(grf_node);
			data->pack = grf_file_get_storage_size(grf_node);
			m_grf_data->Append(data);
			file_count++;
		}
		grf_node = grf_get_file_next(grf_node);
		if (!progress_dialog.Update(progress_dialog.GetValue() + 1))
			break;
	}
	m_grf_list->Resize(file_count);
}

static bool GRFRepackCallback(void *param, GrfFile *grf_handle, int position, int max, const char* file_name)
{
	wxProgressDialog *progress_dialog = (wxProgressDialog*)param;
	progress_dialog->Update(position, _(file_name));
	return true;
}

void MainFrame::FileView()
{
	if (!m_grf_list->GetSelection()) {
		wxMessageBox(_("Please select a file"), _("View File"), wxICON_EXCLAMATION | wxOK);
		return;
	}

	MyData *grf_data = m_grf_data->Item(m_grf_list->GetRow(m_grf_list->GetCurrentItem()))->GetData();
	GrfNode *grf_node = grf_get_file(m_grf_handle, grf_data->name.c_str());
	int file_size = grf_file_get_size(grf_node);
	uint8_t *file_data = new uint8_t[file_size];
	grf_file_get_contents(grf_node, file_data);

	if (!FindWindow(FRAME_VIEW)) {
		m_view = new GRFFrame(this, FRAME_VIEW, wxEmptyString, wxDefaultPosition, wxDefaultSize);
		m_view->Show();
	}
	if (m_grf_list->enc_type == ENC_EUC_KR)
		m_view->SetTitle(wxString(grf_data->name.AfterLast('\\').To8BitData(), wxCSConv(wxFONTENCODING_EUC_KR)));
	else if (m_grf_list->enc_type == ENC_LOCAL)
		m_view->SetTitle(wxString(grf_data->name.AfterLast('\\').To8BitData(), wxConvLocal));
	else
		m_view->SetTitle(grf_data->name.AfterLast('\\'));

	m_view->m_node = grf_node;

	if (grf_data->name.EndsWith(_(".txt")) || grf_data->name.EndsWith(_(".lua")) || grf_data->name.EndsWith(_(".xml")))
		m_view->SetText(wxString(file_data, file_size));
	else if (grf_data->name.EndsWith(_(".spr"))) {
		SprFile *spr_file = new SprFile;
		if (!spr_file->read(file_data, file_size)) {
			wxMessageBox(_("Invalid SPR File"), _("Error"), wxOK | wxICON_ERROR);
			delete spr_file;
		} else
			m_view->SetSprite(spr_file);
	} else if (grf_data->name.EndsWith(_(".bmp"))) {
		wxImage image = GetImageFromMemory((char*)file_data, file_size, wxBITMAP_TYPE_ANY);
		m_view->SetImage(image);
	} else {
		m_view->Close();
		wxMessageBox(_("Unknown File Format"), _("Error"), wxOK | wxICON_ERROR);
	}

	if (m_view)
		m_view->SetFocus();

	delete file_data;
}

void MainFrame::FileInsert(int flag)
{
	switch (flag) {
		case INSERT_GRF:
		{
			GrfFile *grf_handle;
			GrfNode *grf_node;
			wxString grf_path;
			wxFileDialog file_open_dialog(NULL, _("Load"), m_config->Read("History/LastDirectory"), wxEmptyString, _("GRF Files (*.grf; *.gpf)|*.grf;*.gpf"), wxFD_OPEN | wxFD_FILE_MUST_EXIST);
			if (file_open_dialog.ShowModal() == wxID_OK) {
				grf_path = file_open_dialog.GetPath();
				m_config->Write("History/LastDirectory", file_open_dialog.GetDirectory());
			} else return;

			grf_handle = grf_load(grf_path.mb_str(), false);
			if (grf_handle == NULL)
				return;

			wxProgressDialog progress_dialog(_("Inserting from ") + grf_path, wxEmptyString, grf_filecount(grf_handle), this, wxPD_AUTO_HIDE | wxPD_CAN_ABORT);
			grf_node = grf_get_file_first(grf_handle);
			while (grf_node != NULL) {
				if (!progress_dialog.Update(progress_dialog.GetValue()+1, grf_file_get_filename(grf_node)))
					break;
				int file_size = grf_file_get_size(grf_node);
				uint8_t *file_data = new uint8_t[file_size];
				grf_file_get_contents(grf_node, file_data);
				grf_file_add(m_grf_handle, grf_file_get_filename(grf_node), file_data, file_size);
				grf_node = grf_get_file_next(grf_node);
				delete file_data;
			}
			progress_dialog.Update(progress_dialog.GetRange());
			grf_free(grf_handle);
		} break;
		case INSERT_DIR:
		{
			wxString file_path;
			wxArrayString file_string;
			int path_length;

			wxDirDialog dir_dialog(this, _("Insert from:"), wxEmptyString, wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST);
			if (dir_dialog.ShowModal() == wxID_OK)
				file_path = dir_dialog.GetPath();
			else return;

			path_length = file_path.BeforeLast('\\').length() + 1;
			wxDir::GetAllFiles(file_path, &file_string, _("*.*"));
			wxProgressDialog progress_dialog(_("Inserting from ") + file_path, wxEmptyString, file_string.GetCount(), this, wxPD_AUTO_HIDE | wxPD_CAN_ABORT);
			for (int i = 0; i < file_string.GetCount(); i++) {
				wxString file_name = file_string.Item(i).c_str();
				file_name.Remove(0, path_length);
				if (!progress_dialog.Update(i, file_name))
					break;
				wxFile file_input(file_string.Item(i));
				file_name = wxString(file_name.utf8_str(), wxConvUTF8).mb_str(wxCSConv(wxFONTENCODING_EUC_KR)); // Convert Unicode -> ANSI
				if (file_name == "") {
					file_name = file_string.Item(i).c_str();
					file_name.Remove(0, path_length);
				}
				grf_file_add_fd(m_grf_handle, file_name, file_input.fd());
				file_input.Close();
			}
			progress_dialog.Update(progress_dialog.GetRange());
		} break;
		default:
			return;
	}

	GRFRead();
}

void MainFrame::FileRepack(int flag)
{
	wxProgressDialog progress_dialog(_("Repacking"), wxEmptyString, m_grf_data->GetCount(), NULL, wxPD_AUTO_HIDE);
	grf_set_callback(m_grf_handle, GRFRepackCallback, (void*) &progress_dialog);
	grf_repack(m_grf_handle, flag);
}

bool MainFrame::FileExtract(GrfNode *grf_node, wxString file_path, int flag)
{
	wxFile file;
	wxFileName file_name;
	switch (flag) {
		case 0:
			file_path = wxString(file_path.To8BitData(), wxCSConv(wxFONTENCODING_EUC_KR));
			file_name.Assign(file_path);
			if (!file_name.DirExists())
				file_name.Mkdir(511, wxPATH_MKDIR_FULL);
			if (!file.Create(file_path))
				return false;
			if (grf_file_put_contents_to_fd(grf_node, file.fd()) != grf_file_get_size(grf_node))
				return false;
			file.Close();
			break;
		case 1:
			if (!grf_put_contents_to_file(grf_node, file_path))
				return false;
		default:
			break;
	} return true;
}

void MainFrame::DialogExtract()
{
	wxDataViewItemArray data_list_item;
	m_grf_list->GetSelections(data_list_item);
	if (!m_grf_data->GetCount()) {
		wxMessageBox(_("GRF List is empty"), _("Extract File"), wxICON_EXCLAMATION | wxOK);
		return;
	}
	if (!data_list_item.Count()) {
		wxMessageBox(_("No File Selected"), _("Extract File"), wxICON_EXCLAMATION | wxOK);
		return;
	}
	GRFDialog dialog_extract(this, DIALOG_EXTRACT, _("Extract File"), wxDefaultPosition, wxSize(300, 150));
	int flag = dialog_extract.ShowModal();
	if (flag != -1) {
		m_config->Write(_("/Settings/ExtractWithDirectory"), (flag&EXTRACT_WITH_DIRECTORY) ? true : false);
		m_config->Write(_("/Settings/ExtractConvertToANSI"), (flag&EXTRACT_CONVERT_ASCII) ? true : false);
		// Run process on another thread
		WorkerThread *thread = new WorkerThread(this, flag);
		thread->Create();
		thread->Run();
	}
}

void MainFrame::DialogDelete()
{
	wxDataViewItemArray data_list_item;
	m_grf_list->GetSelections(data_list_item);
	if (!data_list_item.Count()) {
		wxMessageBox(_("No File Selected"), _("Delete File"), wxICON_EXCLAMATION | wxOK);
		return;
	}

	if (wxMessageBox(_("Do you want to delete selected files?"), _("Delete File"), wxICON_QUESTION | wxYES_NO) == wxYES) {
		OnDelete();
	}
}

void MainFrame::DialogSetting()
{
	GRFDialog dialog_extract(this, DIALOG_SETTING, _("Settings"), wxDefaultPosition, wxSize(400, 275));
	dialog_extract.ShowModal();
	if (!m_grf_data->IsEmpty())
		grf_set_compression_level(m_grf_handle, m_config->ReadLong(_("/Settings/CompressionLevel"), 5));
}

void MainFrame::SettingsLoad()
{
	wxFile config_file;
	if (!wxFileExists(_(CONFIG_FILENAME))) {
		config_file.Open(_(CONFIG_FILENAME), wxFile::write);
		config_file.Close();
		wxFileStream config_stream(_("config"));
		m_config = new wxFileConfig(config_stream);
		m_config->Write(_("/Settings/CompressionLevel"), 5);
		m_config->Write(_("/Settings/RepackType"), GRF_REPACK_FAST);
		m_config->Write(_("/Settings/Encoding"), (int)ENC_LOCAL);
		m_config->Write(_("/Settings/ExtractWithDirectory"), true);
		m_config->Write(_("/Settings/ExtractConvertToANSI"), true);
		m_config->Write(_("/Settings/Language"), _("en"));
		m_config->Write(_("/History/LastDirectory"), wxGetCwd());
		m_config->Save(wxFileStream(_(CONFIG_FILENAME)));
	} else {
		wxFileStream config_stream(_(CONFIG_FILENAME));
		m_config = new wxFileConfig(config_stream);
	}
}

void MainFrame::SettingsSave()
{
	//Clear config file
	wxFile file_config;
	file_config.Create(CONFIG_FILENAME, true);
	file_config.Close();

	m_config->Save(wxFileStream(_(CONFIG_FILENAME)));
}

void MainFrame::DataClear()
{
	m_grf_data->DeleteContents(true);
	m_grf_data->Clear();
}

WorkerThread::WorkerThread(MainFrame *frame, int flag)
	:wxThread()
{
	m_frame = frame;
	m_flag  = flag;
}

wxThread::ExitCode WorkerThread::Entry()
{
	m_frame->OnExtract();

	return NULL;
}

wxString GetExtension(const char *filename)
{
	uint32_t i;
	char extension[UCHAR_MAX];
	memset(extension, '\0', sizeof(extension));
	for (i = strlen(filename); i > 0; i--) {
		if (filename[i] == '.') {
			i++;
			memcpy(extension, filename+i, strlen(filename)-i);
			     if (strncmp(strlwr(extension), "txt", 3) == 0) return _("Text");
			else if (strncmp(strlwr(extension), "spr", 3) == 0) return _("Sprite");
			else if (strncmp(strlwr(extension), "str", 3) == 0) return _("Special Trail Resource");
			else if (strncmp(strlwr(extension), "imf", 3) == 0) return _("Interact Manage File");
			else if (strncmp(strlwr(extension), "pal", 3) == 0) return _("Palette");
			else if (strncmp(strlwr(extension), "act", 3) == 0) return _("Action");
			else if (strncmp(strlwr(extension), "png", 3) == 0) return _("PNG Image");
			else if (strncmp(strlwr(extension), "bmp", 3) == 0) return _("Bitmap");
			else if (strncmp(strlwr(extension), "lua", 3) == 0) return _("Lua");
			else if (strncmp(strlwr(extension), "lub", 3) == 0) return _("Lua Binary");
			else if (strncmp(strlwr(extension), "gat", 3) == 0) return _("Ground Altitude");
			else if (strncmp(strlwr(extension), "rsw", 3) == 0) return _("Resource World");
			else if (strncmp(strlwr(extension), "rsm", 3) == 0) return _("Resource Model");
			else if (strncmp(strlwr(extension), "gnd", 3) == 0) return _("Ground Map");
			else if (strncmp(strlwr(extension), "gr2", 3) == 0) return _("Granny 2 Model");
			else if (strncmp(strlwr(extension), "ezv", 3) == 0) return _("Scripting Vector");
			else if (strncmp(strlwr(extension), "tga", 3) == 0) return _("Targa Graphic");
			else if (strncmp(strlwr(extension), "jpg", 3) == 0) return _("JPEG Image");
			else {
				memmove(extension, extension-1, (strlen(filename)-i)+1);
				extension[0] = '.';
				return _(extension);
			} break;
		}
	} return "Unknown";
}

wxString ConvertByte(uint64_t size_real, uint64_t size_compressed)
{
	char n = 0;
	double size_real_double = size_real;
	while (size_real_double > 1024) {
		size_real_double = size_real_double / 1024;
		n++;
	}
	if (size_compressed == 0)
		return wxString(wxString::Format("%.2f ", size_real_double) +
	                   (n == 0 ? _("B"):
	                    n == 1 ? _("kB"):
	                    n == 2 ? _("mB"):
	                    n == 3 ? _("gB"):_("tB")));
	else
		return wxString(wxString::Format("%.2f / ", size_real_double) + wxString::Format("%.2f ", (double)size_compressed/pow(1024.0, n)) +
	                   (n == 0 ? _("B"):
	                    n == 1 ? _("kB"):
	                    n == 2 ? _("mB"):
	                    n == 3 ? _("gB"):_("tB")));
}

bool MyApp::OnInit()
{
	wxImage::AddHandler(new wxPNGHandler());

	MainFrame *main_frame = new MainFrame(_("FEGRF"), wxDefaultPosition, wxSize(640, 400));
	main_frame->Show();

	return true;
}